//Author: ChenL

package org.globalplatform;

import com.wk.javacard.vnative.VN;
import javacard.framework.*;
import wk.globalplatform.*;
class ISDSecureChannel implements SecureChannel {

	//private static byte isAuthenticated = 0x00;
	//construction function
	ISDSecureChannel(){
		VN.native_FrameWork_JCSystem_setJCREEntry(this, false);
	}

	public short decryptData(byte[] baBuffer, short sOffset, short sLength)throws ISOException{
		//-call native method to decrypt indicated byte array's data
		//The decrypt Data will replace the locate byte array

    	//byte bTemp = baBuffer[sOffset];
    	//bTemp = baBuffer[(short)(sLength - 1)];
    	//bTemp = baBuffer[(short)(sOffset + sLength - 1)];
		//short sReturn = VN.native_OP_decryptData(baBuffer, sOffset, sLength);
		//if (sReturn == (short)-1)
		//	ISOException.throwIt(ISO7816.SW_DATA_INVALID);
		//return sReturn;
		return VN.native_OP_decryptData_CT();

	}

	public short encryptData(byte[] baBuffer, short sOffset, short sLength)throws ArrayIndexOutOfBoundsException{
		//call native method to encrypt data
    	//byte bTemp = baBuffer[sOffset];
    	//bTemp = baBuffer[(short)(sLength - 1)];
    	//bTemp = baBuffer[(short)(sOffset + sLength - 1)];
		//short sTmp ;
		//sTmp = (short)(8 - (sLength%8));
		//sTmp = (short)(sTmp + sLength);
		//byte bTmp = baBuffer[(short)(sOffset + sTmp)];//If cause access outside array bounds, Will auto throw ArrayIndexOutOfBoundsException


		//return VN.native_OP_encryptData(baBuffer, sOffset, sLength);

		return VN.native_OP_encryptData_CT();
	}

	public byte  getSecurityLevel(){
		//
		//more levels will return
		// 0xB0 --> AUTHENICATED, R_ENCRYPTION and R_MAC
		// 0x83 --> AUTHENICATED, C_DECRYPTION and C_MAC
		// 0x03 --> C_DECRYPTION and C_MAC
		// 0x30 --> R_ENCRYPTION and R_MAC
		// ... ...

		return VN.native_OP_getSecurityLevel();
	}

	public short processSecurity(javacard.framework.APDU apdu) throws ISOException{
	
		byte bCLA;
		Object obj ;
		byte[] apduBuffer ;
		byte[] bHash = null;
		byte[] bSign = null;
		
		
		apduBuffer = apdu.getBuffer();
		bCLA = apduBuffer[ISO7816.OFFSET_CLA];
        
		if(bCLA != (byte)0x80 && bCLA != (byte)0x84){
			ISOException.throwIt(ISO7816.SW_CLA_NOT_SUPPORTED);
		}
		//support Delegate Management
		//1. Get indicate SD object
		//2. Prepare Derivation Data and Load File Data Hash
		//3. call SD.verifyDAP(byte[] der, byte[] signature)
		//4. 
				
		
		
		switch(apduBuffer[ISO7816.OFFSET_INS])
		{
/*****************			
			case (byte)0xE8://GP_INS_LOAD:
				if(getSecurityLevel()<AUTHENTICATED)
					ISOException.throwIt((short)0x6985);
				try{
					VN.native_OP_PreLoad();
					while(true){
						obj = VN.native_OP_getDAPSD();
						if(obj == null)
							break;
						if(((DAPSecurityDomain)obj).verifyDAP(bHash, bSign))
							ISOException.throwIt((short)0x6982);
					}
					VN.native_OP_PostLoad(true);
					return 0;
				}catch(Exception e){
					VN.native_OP_PostLoad(false);
					ISOException.throwIt((short)0x6985);	
				}		
						
			case (byte)0xE6://GP_INS_INSTALL:
			case (byte)0xE4://GP_INS_DELETE:
				if(getSecurityLevel()<AUTHENTICATED)
					ISOException.throwIt((short)0x6985);
*******************/
			case (byte)0x50://GP_InitializeUpdate:
			case (byte)0x82://GP_ExternalAuthenticate:
				//return ;
		}
		
		
		return VN.native_OP_processSecurity();
		
	}

	public void  resetSecurity(){
		//do final security.
		VN.native_OP_resetSecurity();
	}

	public short unwrap(byte[] baBuffer, short sOffset, short sLength)throws ISOException{
		//when incoming command will call this method
		//At this time, already call processSecurity(byte[]) method. the SecurityDomain has generated session key.
    	//byte bTemp = baBuffer[sOffset];
    	//bTemp = baBuffer[(short)(sLength - 1)];
    	//bTemp = baBuffer[(short)(sOffset + sLength - 1)];
        //
        //
		//short sReturn = VN.native_OP_unwrap(baBuffer, sOffset, sLength);
		//if(sReturn == (short)0){
		//	ISOException.throwIt(ISO7816.SW_SECURITY_STATUS_NOT_SATISFIED);
		//}else if (sReturn == (short)-1){
		//	ISOException.throwIt(ISO7816.SW_WRONG_DATA );
		//}
		//return sReturn;
		return VN.native_OP_unwrap_CT();
	}

	public short wrap(byte[] baBuffer, short sOffset, short sLength)throws ArrayIndexOutOfBoundsException, ISOException{
		//when outgoing will call this method

		// if crrent security level is NONE, will do no process.
    	//byte bTemp = baBuffer[sOffset];
    	//bTemp = baBuffer[(short)(sLength - 1)];
    	//bTemp = baBuffer[(short)(sOffset + sLength - 1)];
        //
		//short sTmp ;
		//sTmp = (short)((short)8 - (sLength%8));
		//sTmp = (short)(sTmp + sLength);
		//byte bTmp = baBuffer[(short)(sOffset + sLength)];// If cause access outside array bounds, Will auto throw ArrayIndexOutOfBoundsException
        //
		//short sReturn = VN.native_OP_wrap(baBuffer, sOffset, sLength);
		//if(sReturn == (short)0){
		//	ISOException.throwIt(ISO7816.SW_SECURITY_STATUS_NOT_SATISFIED);
		//}else if (sReturn == (short)-1){
		//	ISOException.throwIt(ISO7816.SW_WRONG_DATA );
		//}
		//return sReturn;
		return VN.native_OP_wrap_CT();
	}


}
